﻿using System.Collections;
using System.Collections.Generic;
using Gameplay.PVE;
using UnityEngine;

[ExecuteInEditMode]
public class CityParticleAnimation : MonoBehaviour {
 
    [Header("播放时间")]
    public float lifeTime = 1;
    
    //[Tooltip("Tooltip_test")]
    [Header("是否循环")]
    public bool looping = true;


    [Header("颜色")]
    public Color color = Color.white;

    [Header("TillingOffset(tiling小于10)")]
    public Vector4 tillingOffset = new Vector4(1,1,0,0);

    [Header("是否播放序列帧")]
    public bool isFrameAnimation = false;

    [Header("序列帧")]
    [Tooltip("格子列数")]
    public int gridX = 4;
    [Tooltip("格子行数")]
    public int gridY = 4;

    [Tooltip("起始序列")]
    public int startFrame = 0;
    [Tooltip("结束序列")]
    public int endFrame = 3; 
    
    //float 
    float interval;
    int frame = -1;
    float _time;
    bool finished = false;

    /// <summary>
    /// 
    /// </summary>
    Vector2 tilling = new Vector2(1,1);
    Vector2 offset = new Vector2(0,0);

    [Header("缩放")]
    public bool isScale = false;
    public AnimationCurve scaleCurveX ;
    public AnimationCurve scaleCurveY;
    public AnimationCurve scaleCurveZ;

    [Header("Gradient")]
    public bool isGradientColor = true;
    public Gradient gradientColor;
   
    [Header("是否Billboard")]
    public bool isBillboard = true;
    [Header("是否Y轴Billboard")]
    public bool isYBoardboard = true;


    MeshRenderer _meshRender;
    Transform _transform;

    const float MAX_DISTANCE = 20;
    bool isCull = false;

    Material m_mat;

    private void Awake()
    {
        _meshRender = GetComponent<MeshRenderer>();
        _transform = GetComponent<Transform>();
    }

    // Use this for initialization
    void Start () {
       
        if(endFrame >= gridX * gridY)
        {
            endFrame = gridX * gridY - 1;
        }
        interval = lifeTime / (endFrame - startFrame);
        tilling = new Vector2(1 / gridX, 1 / gridY);

        _time = 0;

#if UNITY_EDITOR
        if (Application.isPlaying && !IsVertexDataPack)
        {
            if (!_meshRender.material.name.Contains("Instance"))
            {
                m_mat = _meshRender.sharedMaterial;
                Material mat = new Material(_meshRender.material);
                _meshRender.sharedMaterial = mat;
            }
            else
            {
                Debug.LogWarning("error :meshRender.material.name.Contains(Instance)");
            }
        }
   

#endif

        //if (isGradientColor)
        //{
        //    meshRender.sharedMaterial.SetColor("_Color", color);
        //}
        //else
        //{
        //    meshRender.sharedMaterial.SetColor("_Color", color);
        //}

        ChangeColor(color);
        if (!isFrameAnimation)
        {
            //meshRender.sharedMaterial.SetTextureScale("_MainTex", new Vector2(this.tillingOffset.x, this.tillingOffset.y));
            //meshRender.sharedMaterial.SetTextureOffset("_MainTex", new Vector2(this.tillingOffset.z, this.tillingOffset.w));
            ChageTilingOffset(new Vector2(this.tillingOffset.x, this.tillingOffset.y), new Vector2(this.tillingOffset.z, this.tillingOffset.w));
        }
    

    }

    static Vector4 vector4Null = new Vector4(float.MinValue, float.MinValue, float.MinValue, float.MinValue);

    [System.NonSerialized]
    Vector2 mainTiling;
    [System.NonSerialized]
    Vector2 mainOffset;
    [System.NonSerialized]
    Color tintColor;
    [System.NonSerialized]
    List<Vector4> uvBuffer = new List<Vector4>();
    [System.NonSerialized]
    Vector4 _pack1 = vector4Null;
    [System.NonSerialized]
    Mesh sharedMesh = null;
    [System.NonSerialized]
    MeshFilter filter = null;

    const float TexOffsetRange = 1.0f;
    const float TexScaleRange = 10.0f;
    const float mColorRange = 10.0f;
    static int offsetMul = Shader.PropertyToID("offsetMul");
    static int offsetAdd = Shader.PropertyToID("offsetAdd");

    public Vector4 MainBlock = new Vector4(1, 1, 0, 0);
    public bool IsVertexDataPack = false;
    private void OnEnable()
    {
        if (Application.isPlaying  && IsVertexDataPack)
        {
            float a1 = EffectMeshUtility.V2Tofloat(MainBlock.x, MainBlock.y);
            float a2 = EffectMeshUtility.V2Tofloat(MainBlock.z, MainBlock.w);
            Vector2 _pack0 = new Vector2(a1, a2);

            if(sharedMesh == null)
            {
                filter = GetComponent<MeshFilter>();
                sharedMesh = filter.sharedMesh;
                filter.sharedMesh = Mesh.Instantiate(sharedMesh);

                filter.sharedMesh.GetUVs(0, uvBuffer);
                for (int i = 0; i < uvBuffer.Count; i++)
                {
                    Vector4 tex = uvBuffer[i];
                    tex.z = _pack0.x;
                    tex.w = _pack0.y;
                    uvBuffer[i] = tex;
                }
                filter.sharedMesh.SetUVs(0, uvBuffer);

                Renderer re = gameObject.GetComponent<Renderer>();
                if (re != null)
                {
                    re.sharedMaterial.SetFloat(offsetMul, 2.0f * TexOffsetRange);
                    re.sharedMaterial.SetFloat(offsetAdd, -TexOffsetRange);
                }
            }
        }
    }

    void OnDestroy()
    {
        if (sharedMesh != null && filter != null)
        {
            if (filter.sharedMesh != null && sharedMesh != filter.sharedMesh)
            {
                Object.DestroyImmediate(filter.sharedMesh);
            }

            filter.sharedMesh = sharedMesh;
            sharedMesh = null;
            filter = null;
        }
        else if (Application.isPlaying)
        {
            if (m_mat)
            {
                _meshRender.sharedMaterial = m_mat;
            }
        }
    }

    // Update is called once per frame
    void Update () {

#if UNITY_EDITOR
        interval = lifeTime / (endFrame - startFrame);
        tilling = new Vector2(1.0f / gridX, 1.0f / gridY);
        if (endFrame >= gridX * gridY)
        {
            endFrame = gridX * gridY - 1;
        }

        if(looping)
        {
            finished = false;
            
        }

        if (!isFrameAnimation)
        {
            //meshRender.sharedMaterial.SetTextureScale("_MainTex", new Vector2(this.tillingOffset.x, this.tillingOffset.y));
            //meshRender.sharedMaterial.SetTextureOffset("_MainTex", new Vector2(this.tillingOffset.z, this.tillingOffset.w));
            ChageTilingOffset(new Vector2(this.tillingOffset.x, this.tillingOffset.y), new Vector2(this.tillingOffset.z, this.tillingOffset.w));
        }

        if(!isGradientColor)
        {
            //meshRender.sharedMaterial.SetColor("_Color", color);
            ChangeColor(color);
        }
#endif



        if (finished)
        {
            return;
        }

        if (PveCameraManager.Instance.mainCamera != null)
        {
            float distance = Vector3.Distance(_transform.position, PveCameraManager.Instance.mainCamera.transform.position);

            if (distance > 200)
            {
                if(!isCull)
                {
                    //isCull = true;
                    //meshRender.enabled = false;

                }

                return;
            }
            else
            {
                if(isCull)
                {
                    isCull = false;
                    _meshRender.enabled = true;

                }
            }

        }

        _time += Time.deltaTime;
        if (isFrameAnimation)
        { 
            if (_time > interval)
            {
                frame++;
                if (frame > endFrame)
                {
                    if (looping)
                    {
                        frame = startFrame;
                    }
                    else
                    {
                        finished = true;
                    }
                }
                _time -= interval;
                PlayFrame(frame, _time);
            }
        }
        else
        {
            if (_time > interval)
            {
                finished = true;
            }

        }

        


        if(isBillboard)
        {
            Billboard();
        }


        float _gradientTime = (Time.time % lifeTime) / lifeTime;
        if (isScale)
        {
            Scale(_gradientTime);
        }

        if(isGradientColor)
        {
            GradientAnim(_gradientTime);
        }


        if (sharedMesh != null && filter != null)
        {
            Vector4 color = tintColor;

            float c1 = EffectMeshUtility.PackM(color.x, color.y, mColorRange);
            float c2 = EffectMeshUtility.PackM(color.z, color.w, mColorRange);
            float d1 = EffectMeshUtility.PackScale(mainTiling, TexScaleRange);
            float d2 = EffectMeshUtility.PackOffset(mainOffset, TexOffsetRange);
            Vector4 pack1 = new Vector4(c1, c2, d1, d2);
            if (Vector4.Distance(pack1, _pack1) > float.Epsilon)
            {
                _pack1 = pack1;
                for (int i = 0; i < uvBuffer.Count; i++)
                {
                    uvBuffer[i] = pack1;
                }
                filter.sharedMesh.SetUVs(1, uvBuffer);
            }
        }

    }


    void Billboard()
    {
        if(isYBoardboard)
        {
            Vector3 v = PveCameraManager.Instance.mainCamera.transform.position - _transform.position;
            v.x = v.z = 0.0f;
            _transform.LookAt(PveCameraManager.Instance.mainCamera.transform.position - v);
            
        }
        else
        {
            _transform.LookAt(PveCameraManager.Instance.mainCamera.transform);
        }
    }

    void Scale(float time)
    {
        float x = scaleCurveX.Evaluate(time);
        float y = scaleCurveY.Evaluate(time);
        float z = scaleCurveZ.Evaluate(time);

        _transform.localScale = new Vector3(x,y,z);
    }


    void GradientAnim(float time)
    {
        Color color = gradientColor.Evaluate(time) * this.color;
        ChangeColor(color);
        //meshRender.sharedMaterial.SetColor("_Color",color); 
    }


    void PlayFrame(int frame, float time)
    {
        frame = Mathf.Clamp(frame, 0, gridX * gridY);

        //Debug.Log("PlayFrame:" + frame);
        int y = Mathf.FloorToInt(frame / gridX);
        int x =(int)( frame % gridX);
        y = gridY - y - 1;

        Vector2 offset = new Vector2(x * tilling.x, y * tilling.y);

        //Debug.Log("tiling " + tilling.x +" " +tilling.y + ",offset:" + offset.x + " " + offset.y);

        Vector4 tilingOffset = new Vector4(tilling.x, tilling.y,offset.x, offset.y);
        //meshRender.sharedMaterial.SetVector("_TillingOffset", tilingOffset);
        //meshRender.sharedMaterial.SetTextureScale("_MainTex", tilling);
        //meshRender.sharedMaterial.SetTextureOffset("_MainTex", offset);
        ChageTilingOffset(tilling, offset);


    }

   void ChageTilingOffset(Vector2 tilling,Vector2 offset)
    {
#if UNITY_EDITOR
        if(tilling.x >= 10 || tilling.y >= 10)
        {
            Debug.LogError("tilling 必须小于10...");
        }
#endif
        if (tilling.x < 0 || tilling.y < 0 || offset.x < 0 || offset.y < 0)
        {
            Debug.LogError("tilling 必须大于0...");
        }

        if (IsVertexDataPack)
        {
            mainTiling = tilling;
            mainOffset = offset;
        }
        else
        {
            _meshRender.sharedMaterial.SetTextureScale("_MainTex", tilling);
            _meshRender.sharedMaterial.SetTextureOffset("_MainTex", offset);
        }
    }


    void ChangeColor(Color color)
    {
        if(IsVertexDataPack)
            tintColor = color;
        else
            _meshRender.sharedMaterial.SetColor("_TintColor", color);
    }
}
